package com.dog.modules.websocket.handler;

import com.alibaba.fastjson2.JSON;
import com.dog.framework.core.enums.PlatformEnum;
import com.dog.modules.websocket.config.WsSessionManager;
import com.dog.modules.websocket.constant.Constants;
import com.dog.modules.websocket.constant.RedisKeyPrefixConst;
import com.dog.modules.websocket.domain.WsMsgType;
import com.dog.modules.websocket.domain.WsPayload;
import com.dog.modules.websocket.domain.enums.ClientTypeEnum;
import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;




/**
 * Biz websocket Handler
 */
@Component
@Slf4j
public class BizSSHSocketHandler extends TextWebSocketHandler {

    public static Integer TOKEN_EXPIRE_TIME = 15 * 24 * 60 * 60 * 1000;

    @Autowired
    private WsSessionManager wsSessionManager;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;


    ThreadPoolExecutor executor = new ThreadPoolExecutor(
            10,
            100,
            1,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(1000), new DefaultThreadFactory("BizSshSocketThread"));

    /**
     * socket 建立成功事件
     *
     * @param webSocketSession
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) {
        Long userId = (Long) webSocketSession.getAttributes().get(Constants.PARAM_KEY_USER_ID);
        String key = String.format(RedisKeyPrefixConst.WS_USERID_SESSION, PlatformEnum.MERCHANT.getCode() +
                ":" + userId);
        redisTemplate.opsForValue().set(key, webSocketSession.getId(), TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
        // 用户连接成功，放入在线用户缓存
        wsSessionManager.add(ClientTypeEnum.BIZ.getCode(), webSocketSession.getId(), webSocketSession);
    }

    /**
     * socket 断开连接时
     *
     * @param webSocketSession
     * @param closeStatus
     */
    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        // 用户退出，移除缓存
        wsSessionManager.removeAndClose(ClientTypeEnum.BIZ.getCode(), webSocketSession.getId());
    }

    /**
     * 根据session id推送消息
     *
     * @param sessionId
     * @param payload
     */
    public void sendMessage(String sessionId, WsPayload payload) {
        WebSocketSession session = wsSessionManager.getSession(ClientTypeEnum.BIZ.getCode(), sessionId);
        wsSessionManager.sendMessage(session, payload);
    }

    /**
     * 接收消息事件
     *
     * @param webSocketSession
     * @param webSocketMessage
     * @throws Exception
     */
    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage webSocketMessage) throws Exception {
        // 消息内容
        String reqPayloadStr = webSocketMessage.getPayload().toString();
        WsPayload reqPayload = JSON.parseObject(reqPayloadStr, WsPayload.class);
        log.info("receive msg: {} from biz client {}", reqPayloadStr, webSocketSession.getId());
        executor.execute(() -> {
            WsPayload respPayload = null;
            switch (WsMsgType.valueOf(reqPayload.getType())) {
                case HEARTBEAT:
                    respPayload = handleHeartBeat();
                    break;
                default:
                    break;
            }
            wsSessionManager.sendMessage(webSocketSession, respPayload);
        });
    }



    private WsPayload handleHeartBeat() {
        WsPayload respPayload = new WsPayload();
        respPayload.setType(WsMsgType.HEARTBEAT.getCmd());
        respPayload.setTimestamp(System.currentTimeMillis());
        return respPayload;
    }






}
